package auth

import (
  "context"
  "fmt"
  "pay/collector/logger"
  "pay/config"
  "pay/errors"
  "pay/lib/token"
  "pay/lib/token/jwt"
  "time"
)

const (
  AuthUserKey = "auth_user_key"
  AuthOsKey   = "auth_os_key"
)

type TokenDataKey struct{}

var auth token.Provider

type Options struct {
  UserID uint `json:"user_id"`
}

func Init() func() {
  fmt.Println("auth init...")
  auth = jwt.NewTokenProvider(token.WithPrivateKey(config.Conf.JwtToken.PrivateKey), token.WithPublicKey(config.Conf.JwtToken.PublicKey))
  return func() {}
}

func Generate(options *Options, expire time.Duration) (*token.Token, error) {
  user := &token.UserClaims{
    UserID: options.UserID,
  }

  return auth.Generate(user, token.WithExpiry(expire))
}

func Refresh(tk string) (*token.Token, error) {
  return auth.Refresh(tk)
}

func Verify(tk string) error {
  _, err := auth.Parse(tk)
  if err != nil {
    return err
  }
  return nil
}

func Extract(tk string) (*Options, error) {
  var (
    err  error
    data *token.UserClaims
  )
  if data, err = auth.Parse(tk); err != nil {
    return nil, err
  }

  return &Options{UserID: data.UserID}, nil
}

func ExtractDataFromCtx(ctx context.Context) (*Options, error) {
  var (
    ok   bool
    opts = &Options{}
  )
  value := ctx.Value(TokenDataKey{})
  if opts, ok = value.(*Options); ok {
    return opts, nil
  }
  return nil, errors.New("context does not contain token data")
}

// ContextUserID context获取用户id
func ContextUserID(ctx context.Context) (uint, error) {
  var (
    userId uint
    err    error
  )

  value := ctx.Value(AuthUserKey)
  userId, ok := value.(uint)
  if !ok {
    if value != nil {
      logger.Errorf("context user id type err %T", value)
    }
    return userId, errors.New("token err")
  }
  return userId, err
}
